using System;
using System.Collections.Generic;
using System.Text;

namespace OracleInternal.I18N
{
	[Serializable]
	internal abstract class Conv
	{
		public delegate int DelegateReplaceCharsInSB(StringBuilder sb, char[] strArray, int offset, int arrayCount, char[] charsToMatch, string[] stringsToReplaceWith);

		public const int CONCAIN_CHARSET_TABLE = 2;

		public const int AL16UTF16_CHARSET = 2000;

		public const int AL16UTF16LE_CHARSET = 2002;

		public const int UNICODE_1_CHARSET = 870;

		public const int UNICODE_2_CHARSET = 871;

		public const int UTFE_CHARSET = 872;

		public const int AL32UTF8_CHARSET = 873;

		public const int ISO2022JP_CHARSET = 9999;

		public const int ISO2022_JP_OUTLOOK_CHARSET = 9994;

		public const int ISO2022_JP_OUTLOOK_HWKANA_CHARSET = 9995;

		public const char UTF16_REPLACEMENT_CHAR = '\ufffd';

		public const byte UTF16_REPLACEMENT_HIGH_BYTE = byte.MaxValue;

		public const byte UTF16_REPLACEMENT_LOW_BYTE = 253;

		public const int WE8DECTST = 798;

		public const int ZHT32EUCTST = 993;

		public const int WE16DECTST2 = 994;

		public const int WE16DECTST = 995;

		public const int KO16TSTSET = 996;

		public const int JA16TSTSET2 = 997;

		public const int JA16TSTSET = 998;

		public const int US16TSTFIXED = 1001;

		public const int UTF16 = 1000;

		public const int HZ_GB_2312 = 9996;

		public const int ISO2022_KR = 9997;

		public const int ISO2022_CN = 9998;

		public const bool USE_REPLACEMENT = true;

		private const int s_charsRequestedLength = 32768;

		protected static readonly byte[] REP_CHAR_UTF8 = new byte[3]
		{
			239,
			191,
			189
		};

		private static Dictionary<int, Conv> s_oraCharsetCache = new Dictionary<int, Conv>();

		private static readonly TLBConvBoot s_bootObj = TLBConvBoot.GetInstance();

		private static readonly HashSet<int> UNSUPPORTED_CHARSET = new HashSet<int>
		{
			798,
			993,
			994,
			995,
			996,
			997,
			998,
			1001,
			1000,
			9996,
			9997,
			9998
		};

		public int OracleId
		{
			get;
			set;
		}

		public abstract int MinBytesPerChar
		{
			get;
		}

		public abstract int MaxBytesPerChar
		{
			get;
		}

		protected Conv()
		{
		}

		protected Conv(int oracleId)
		{
			OracleId = oracleId;
		}

		public static Conv GetInstance(int charsetId)
		{
			Conv value = null;
			if (UNSUPPORTED_CHARSET.Contains(charsetId))
			{
				return null;
			}
			lock (s_oraCharsetCache)
			{
				if (s_oraCharsetCache.TryGetValue(charsetId, out value))
				{
					return value;
				}
				switch (charsetId)
				{
				case 870:
				case 871:
					value = new UTF16ConvUTF8(870);
					break;
				case 872:
					value = new UTF16ConvUTFE(872);
					break;
				case 873:
					value = new UTF16ConvAL32UTF8(873);
					break;
				case 2000:
					value = new UTF16ConvAL16UTF16(2000);
					break;
				case 2002:
					value = new UTF16ConvAL16UTF16LE(2002);
					break;
				default:
					value = TLBConv.GetGLBInstance(charsetId);
					break;
				}
				s_oraCharsetCache.Add(charsetId, value);
				return value;
			}
		}

		public static int GetMaxBytesPerChar(int charsetId)
		{
			switch (charsetId)
			{
			case 870:
			case 871:
				return 3;
			case 872:
				return 4;
			case 873:
				return 4;
			case 2000:
			case 2002:
				return 2;
			default:
				return Convert.ToInt32(s_bootObj.GetCharsetMaxCharLen(Convert.ToString(charsetId)));
			}
		}

		public abstract int ConvertBytesToChars(byte[] bytes, int byteOffset, int byteCount, char[] chars, int charOffset, ref int charCount, bool bUseReplacementChar = true);

		internal virtual int ConvertBytesToChars(byte[] bytes, int byteOffset, int byteCount, char[] chars, int charOffset, ref int charCount, ref bool shiftIn, bool bUseReplacementChar = true)
		{
			return 0;
		}

		public int ConvertBytesToChars(ArraySegment<byte> bytes, char[] chars, int charOffset, ref int charCount, bool bUseReplacementChar = true)
		{
			return ConvertBytesToChars(bytes.Array, bytes.Offset, bytes.Count, chars, charOffset, ref charCount, bUseReplacementChar);
		}

		public int ConvertBytesToChars(ArraySegment<byte> bytes, int bytesOffset, int bytesCount, char[] chars, int charOffset, ref int charCount, bool bUseReplacementChar = true)
		{
			return ConvertBytesToChars(bytes.Array, bytes.Offset + bytesOffset, bytesCount, chars, charOffset, ref charCount, bUseReplacementChar);
		}

		public abstract int ConvertBytesToChars(IList<ArraySegment<byte>> bytes, int bytesOffset, int bytesCount, char[] chars, int charOffset, ref int charCount, bool bUseReplacementChar = true);

		internal virtual int ConvertBytesToChars(IList<ArraySegment<byte>> bytes, int bytesOffset, int bytesCount, char[] chars, int charOffset, ref int charCount, ref bool shiftIn, bool bUseReplacementChar = true)
		{
			return 0;
		}

		public int ConvertBytesToChars(IList<ArraySegment<byte>> bytes, char[] chars, int charOffset, ref int charCount, bool bUseReplacementChar = true)
		{
			int num = 0;
			for (int i = 0; i < bytes.Count; i++)
			{
				num += bytes[i].Count;
			}
			return ConvertBytesToChars(bytes, 0, num, chars, charOffset, ref charCount, bUseReplacementChar);
		}

		public void ConvertBytesToStringSB(StringBuilder output, byte[] bytes, int byteOffset, int byteCount, ref int charsConverted, char[] charOutput = null, int offsetOutput = 0, DelegateReplaceCharsInSB replaceDelegate = null, bool bUseReplacementChar = true)
		{
			charsConverted = 0;
			int num = 0;
			int num2 = 0;
			bool shiftIn = true;
			if (charOutput == null)
			{
				num = Math.Min(byteCount / MinBytesPerChar, 32768);
				charOutput = new char[num];
			}
			else
			{
				num = charOutput.Length;
			}
			while (byteCount - num2 != 0)
			{
				int charCount = num;
				num2 = ((!IsShitCharset()) ? (num2 + ConvertBytesToChars(bytes, byteOffset + num2, byteCount - num2, charOutput, offsetOutput, ref charCount, bUseReplacementChar)) : (num2 + ConvertBytesToChars(bytes, byteOffset + num2, byteCount - num2, charOutput, offsetOutput, ref charCount, ref shiftIn, bUseReplacementChar)));
				charsConverted += charCount;
				if (replaceDelegate == null)
				{
					output.Append(charOutput, 0, charCount);
				}
				else
				{
					charsConverted += replaceDelegate(output, charOutput, 0, charCount, null, null);
				}
				if (charCount <= 0)
				{
					break;
				}
			}
		}

		public string ConvertBytesToString(byte[] bytes, int byteOffset, int byteCount, char[] chars = null, bool bUseReplacementChar = true)
		{
			int num = 0;
			int num2 = 0;
			string text = string.Empty;
			bool shiftIn = true;
			if (chars == null)
			{
				num = Math.Min(byteCount / MinBytesPerChar, 32768);
				chars = new char[num];
			}
			else
			{
				num = chars.Length;
			}
			while (byteCount - num2 != 0)
			{
				int charCount = num;
				num2 = ((!IsShitCharset()) ? (num2 + ConvertBytesToChars(bytes, byteOffset + num2, byteCount - num2, chars, 0, ref charCount, bUseReplacementChar)) : (num2 + ConvertBytesToChars(bytes, byteOffset + num2, byteCount - num2, chars, 0, ref charCount, ref shiftIn, bUseReplacementChar)));
				text += new string(chars, 0, charCount);
				if (charCount <= 0)
				{
					break;
				}
			}
			return text;
		}

		public string ConvertBytesToString(IList<ArraySegment<byte>> bytes, int bytesOffset, int bytesCount, char[] chars = null, bool bUseReplacementChar = true)
		{
			int num = 0;
			int num2 = 0;
			string text = string.Empty;
			bool shiftIn = true;
			if (chars == null)
			{
				num = Math.Min(bytesCount / MinBytesPerChar, 32768);
				chars = new char[num];
			}
			else
			{
				num = chars.Length;
			}
			while (bytesCount - num2 != 0)
			{
				int charCount = num;
				num2 = (IsShitCharset() ? ((bytes.Count <= 1) ? (num2 + ConvertBytesToChars(bytes[0].Array, bytes[0].Offset + bytesOffset + num2, bytesCount - num2, chars, 0, ref charCount, ref shiftIn, bUseReplacementChar)) : (num2 + ConvertBytesToChars(bytes, bytesOffset + num2, bytesCount - num2, chars, 0, ref charCount, ref shiftIn, bUseReplacementChar))) : ((bytes.Count <= 1) ? (num2 + ConvertBytesToChars(bytes[0].Array, bytes[0].Offset + bytesOffset + num2, bytesCount - num2, chars, 0, ref charCount, bUseReplacementChar)) : (num2 + ConvertBytesToChars(bytes, bytesOffset + num2, bytesCount - num2, chars, 0, ref charCount, bUseReplacementChar))));
				text += new string(chars, 0, charCount);
				if (charCount <= 0)
				{
					break;
				}
			}
			return text;
		}

		public string ConvertBytesToString(IList<ArraySegment<byte>> bytes, char[] chars = null, bool bUseReplacementChar = true)
		{
			int num = 0;
			for (int i = 0; i < bytes.Count; i++)
			{
				num += bytes[i].Count;
			}
			return ConvertBytesToString(bytes, 0, num, chars);
		}

		public abstract int ConvertBytesToUTF16(byte[] bytes, int byteOffset, int byteCount, byte[] utf16Bytes, int utf16BytesOffset, ref int utf16BytesCount, bool bUseReplacementChar = true);

		public byte[] ConvertBytesToUTF16(byte[] bytes, int byteOffset, int byteCount, bool bUseReplacementChar = true)
		{
			int utf16BytesCount = GetCharsLength(bytes, byteOffset, byteCount) * 2;
			byte[] array = new byte[utf16BytesCount];
			ConvertBytesToUTF16(bytes, byteOffset, byteCount, array, 0, ref utf16BytesCount);
			return array;
		}

		public abstract int ConvertCharsToBytes(char[] chars, int charOffset, int charCount, byte[] bytes, int byteOffset, ref int byteCount, bool bUseReplacementChar = true);

		public abstract int ConvertStringToBytes(string str, int strOffset, int strCount, byte[] bytes, int byteOffset, ref int byteCount, bool bUseReplacementChar = true);

		public byte[] ConvertCharsToBytes(char[] chars, int charOffset, int charCount, bool bUseReplacementChar = true)
		{
			int byteCount = GetBytesLength(chars, charOffset, charCount);
			byte[] array = new byte[byteCount];
			ConvertCharsToBytes(chars, charOffset, charCount, array, 0, ref byteCount, bUseReplacementChar);
			return array;
		}

		public abstract int ConvertUTF16ToBytes(byte[] utf16Bytes, int utf16BytesOffset, int utf16BytesCount, byte[] bytes, int byteOffset, ref int byteCount, bool bUseReplacementChar = true);

		public byte[] ConvertUTF16ToBytes(byte[] utf16Bytes, int utf16BytesOffset, int utf16BytesCount, bool bUseReplacementChar = true)
		{
			int byteCount = GetBytesLength(utf16Bytes, utf16BytesOffset, utf16BytesCount);
			byte[] array = new byte[byteCount];
			ConvertUTF16ToBytes(utf16Bytes, utf16BytesOffset, utf16BytesCount, array, 0, ref byteCount, bUseReplacementChar);
			return array;
		}

		public byte[] ConvertStringToBytes(string str, int strOffset, int strCount, bool bUseReplacementChar = true)
		{
			int byteCount = GetBytesLength(str, strOffset, strCount);
			byte[] array = new byte[byteCount];
			ConvertStringToBytes(str, strOffset, strCount, array, 0, ref byteCount, bUseReplacementChar);
			return array;
		}

		public abstract int GetCharsLength(byte[] bytes, int byteOffset, int byteCount);

		public abstract int GetCharsLength(ArraySegment<byte> bytes, int bytesOffset, int bytesCount);

		public int GetCharsLength(ArraySegment<byte> bytes)
		{
			return GetCharsLength(bytes, 0, bytes.Count);
		}

		public abstract int GetCharsLength(IList<ArraySegment<byte>> bytes, int bytesOffset, int bytesCount);

		public int GetCharsLength(IList<ArraySegment<byte>> bytes)
		{
			int num = 0;
			for (int i = 0; i < bytes.Count; i++)
			{
				num += bytes[i].Count;
			}
			return GetCharsLength(bytes, 0, num);
		}

		public abstract int GetBytesLength(char[] chars, int charOffset, int charCount);

		public abstract int GetBytesLength(string str, int strOffset, int strCount);

		public abstract int GetBytesLength(byte[] utf16Bytes, int utf16BytesOffset, int utf16BytesCount);

		public abstract int GetBytesOffset(byte[] bytes, int byteOffset, int byteCount, int charCount);

		public abstract int GetBytesOffset(IList<ArraySegment<byte>> bytes, int charCount);

		internal virtual bool IsShitCharset()
		{
			return false;
		}
	}
}
